package gggameserver.games.connection;

import gggameserver.exceptions.GGTimeout;
import gggameserver.util.GGUtil;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.List;

public class ProcessConnection implements GGConnection, Runnable {

	private Process process;
	private BufferedReader in;
	private PrintWriter out;
	private BufferedReader inStdErr;
	private Thread stderrThread;

	// TODO delete useless constructors
	// public static ProcessConnection createConnection(String language, String
	// name, String dir) throws IOException {
	// return createConnection(language, name, new File(dir));
	// }
	//
	// public static ProcessConnection createConnection(String language, String
	// name, File dir) throws IOException {
	// if (language.equals("java")) {
	// ArrayList cmds = new ArrayList();
	// cmds.add("java");
	// cmds.add(name);
	// return new ProcessConnection(cmds, dir);
	// } else {
	// return new ProcessConnection(dir + "/" + name, dir);
	// }
	// }

	public ProcessConnection(String cmd, File dir) throws IOException {
		String[] cmds = new String[1];
		cmds[0] = cmd;
		init(cmds, dir);
	}

	public ProcessConnection(List cmd, File dir) throws IOException {
		String[] cmds = new String[cmd.size()];
		for (int i = 0; i < cmd.size(); i++)
			cmds[i] = (String) cmd.get(i);
		init(cmds, dir);
	}

	private void init(String cmd[], File dir) throws IOException {
		this.process = // Runtime.getRuntime().exec(cmd, null, dir);
		GGUtil.exec(cmd, dir);
		this.in = new BufferedReader(new InputStreamReader(
				this.process.getInputStream()));
		this.inStdErr = new BufferedReader(new InputStreamReader(
				this.process.getErrorStream()));
		this.out = new PrintWriter(this.process.getOutputStream(), false);

		stderrThread = new Thread(this);
		stderrThread.setDaemon(true);
		stderrThread.start();
	}

	public void run() {
		String line = null;
		try {
			while (null != (line = inStdErr.readLine())) {
				System.err.println("EEE " + line);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public String receiveCommand(long timeout) throws GGTimeout {
		try {
			System.out.println("PC receive");
			StringBuffer sb = new StringBuffer();
			long start = System.currentTimeMillis();
			while (true) {
				long now = System.currentTimeMillis();
				if (timeout >= 0 && now - start > timeout + 10)
					throw new GGTimeout();
				if (in.ready()) {
					int c = in.read();
					if (c == -1)
						break;
					if (c == '\r')
						continue;
					if (c == '\n')
						break;
					sb.append((char) c);
				} else {
					GGUtil.sleep(10);
				}

				try {
					process.exitValue();
					return null; // can get here only when process exited
				} catch (IllegalThreadStateException e) {
				}
			}
			// todo
			// String cmd = in.readLine();
			String cmd = sb.toString();
			System.out.println("PC <" + cmd);
			; // TODO
			return cmd;
		} catch (IOException e) {
			// TODO receiveCommand
			e.printStackTrace();
			return null;
		}
	}

	public void sendCommand(String cmd) {
		System.out.println("PC send: " + cmd); // TODO
		out.print(cmd);
		out.print('\n');
		out.flush();
		System.out.println("PC send done."); // TODO
	}

	public void close() {
		try {
			process.exitValue();
		} catch (IllegalThreadStateException e) {
			process.destroy();
		} finally {
			out.close();
			try {
				in.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				inStdErr.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}
